<?php


namespace PKApp\Attachment\Classes;


use PKApp\Model\Classes\TraitModel;
use PKCommon\Controller\AdminController;
use PKFrame\DataHandler\Arrays;
use PKFrame\DataHandler\Convert;
use PKFrame\DataHandler\MatchHelper;
use PKFrame\DataHandler\Numbers;

abstract class AttachmentCtrl extends AdminController
{
    use TraitAttachment, TraitModel;

    protected $uploadFile_extension, $uploadFile_name, $uploadFile_type,
        $uploadFile_nameTmp, $uploadFile_md5, $uploadFile_size;
    protected $accept;
    protected $save_fileName;
    protected $pathUrl;
    protected $id_model, $id_field;
    protected $entity_field, $setting_field;
    // 远程图片
    protected $url_img;
    const EXT = 'jpg';

    protected function diskOfPath(): string
    {
//        is_null($dir_name) ?: $dir_name .= DS;
        return PATH_ROOT . str_replace('/', DS, ltrim($this->dirPathOfUrl(), '/'));
    }

    protected function urlOfPath(string $file_name = null): string
    {
        return $this->dirPathOfUrl() . '/' . $file_name;
    }

    protected function dropFile()
    {
        $id = $this->postId('id', 'Empty_id');
        $entity = $this->serviceOfUpload()->interface_getEntityById($id);
        $disk_path = PATH_ROOT . str_replace('/', DS, $entity['url']);
        fileHelper()->UnLink($disk_path);
        $this->serviceOfUpload()->DeleteById($id);
        $this->json();
    }

    protected function getList(string $file_type)
    {
        $this->getPages();
        $params = ['fileType' => $file_type,];
        if ($query = trim(request()->get('query'))) {
            $params[] = ['fileName', 'LIKE', '%' . $query . '%'];
        }
        $count = $this->serviceOfUpload()->Count($params);
        $list = $this->serviceOfUpload()->GetList($params, '*', self::$pageSize, self::$pageIndex);
        $this->json($list, $count);
    }

    protected function paramsOfModelField()
    {
        $this->entity_field = $this->serviceOfField()->GetEntity(['modelId' => $this->id_model, 'field' => $this->id_field]);
        $this->setting_field = $this->entity_field['setting'];
    }

    protected function dirPathOfDisk($is_uploadUri = false): string
    {
        $path_upload = PATH_ROOT;
        if ($this->id_model > 0 && $this->id_field > 0 && is_array($this->setting_field)) {
            // 判断是否为数据模型字段的配置
            if (array_key_exists('savePath', $this->setting_field) && !empty($this->setting_field['savePath'])) {
                MatchHelper::MatchFormat('letterNum', $this->setting_field['savePath'], 'setting_savePath_error', 'model');
                $path_upload .= strtolower($this->setting_field['savePath']);
                fileHelper()->MKDir($path_upload);
            } else {
                $path_upload .= 'upload';
            }
            $path_upload .= DS;
        } else {
            $path_upload .= 'upload' . DS;
        }
        return $path_upload . ($is_uploadUri ? null : date("Ymd") . DS);
    }

    protected function dirPathOfUrl(): string
    {
        if (is_array($this->setting_field)) {
            if (array_key_exists('savePath', $this->setting_field) && !empty($this->setting_field['savePath'])) {
                $path_output = '/' . strtolower($this->setting_field['savePath']) . '/';
            }
        }
        isset($path_output) ?: $path_output = '/upload/';
        return $path_output . (request()->get('action') == 'listimage' ? null : date("Ymd"));
    }

    /**
     * 重新命名
     * @return string
     */
    protected function renameFile(): string
    {
        if ($this->id_model > 0 && $this->id_field > 0
            && is_array($this->setting_field) && array_key_exists('isFromName', $this->setting_field)) {
            return $this->uploadFile_name;
        } else {
            return $this->renameFileOfRand() . '.' . $this->uploadFile_extension;
        }
    }

    protected function renameFileOfRand(): string
    {
        return TIMESTAMP . Numbers::Random(6);
    }

    protected function renameDirOfRand(): string
    {
        return date('Y-m-d') . '-' . Numbers::Random(6);
    }

    protected function requestFile()
    {
        $fileField = request()->controller() == 'AdminUploadByUEditor' ? 'upfile' : 'file';
        array_key_exists($fileField, $_FILES) ?: $this->noticeByJson('ERROR_FILE_NOT_FOUND');
        $upload = $_FILES[$fileField];
        switch ($upload['error']) {
            case UPLOAD_ERR_OK:
                if (is_uploaded_file($upload['tmp_name'])) {
                    $this->uploadFile_name = $upload['name'];
                    $this->uploadFile_nameTmp = $upload['tmp_name'];
                    $this->uploadFile_md5 = md5_file($upload['tmp_name']);
                } else {
                    $this->noticeByJson('ERROR_TMP_FILE_NOT_FOUND');
                }
                // 检查扩展名
                $nameArr = explode(".", $this->uploadFile_name);
                $this->uploadFile_extension = strtolower($nameArr[count($nameArr) - 1]);
                $this->uploadFile_type = $upload['type'];
                $this->_getAllowList_extension();
                $this->uploadFile_size = $upload['size'];
                break;
            case UPLOAD_ERR_INI_SIZE:
                $this->noticeByJson('ERROR_SIZE_EXCEED');
                break;
            case UPLOAD_ERR_FORM_SIZE:
                $this->noticeByJson('uploadFail_formSize');
                break;
            case UPLOAD_ERR_PARTIAL:
                $this->noticeByJson('uploadFail_partial');
                break;
            case UPLOAD_ERR_NO_FILE:
                $this->noticeByJson('uploadFail_noFile');
                break;
            case UPLOAD_ERR_NO_TMP_DIR:
                $this->noticeByJson('uploadFail_noTmpDir');
                break;
        }
    }

    protected function upload(): array
    {
        $this->requestFile();
        $this->save_fileName = $this->renameFile();
        return [
            'url' => $this->urlOfPath($this->save_fileName),
            'md5' => $this->uploadFile_md5,
            'fileType' => $this->accept,
            'fileName' => $this->uploadFile_name,
            'size' => Convert::bytesToUnit($this->uploadFile_size),
            'createTime' => TIMESTAMP,
            'updateTime' => TIMESTAMP,
        ];
    }

    protected function checkReqOfPicUrl()
    {
        !empty($this->url_img) ?: $this->noticeByJson('Empty_url');
        MatchHelper::checkUrlOfDownLoad($this->url_img) ?: $this->noticeByJson('ERROR_urlOfImg');
        //获取请求头并检测死链
        $headers = implode(', ', get_headers($this->url_img));
        if (!(stristr($headers, "200") && stristr($headers, "OK"))) {
            $this->noticeByJson('ERROR_urlOfState');
        }
        //格式验证(扩展名验证和Content-Type验证)
        if (preg_match("/^http(s?):\/\/(mmbiz.qpic.cn)\/(.*)/", $this->url_img) != 1) {
            $this->uploadFile_extension = trim(strtolower(strrchr($this->url_img, '.')), '.');
            if (stristr($headers, "Content-Type: image")) {
                !empty($this->uploadFile_extension) ?: $this->uploadFile_extension = self::EXT;
                if (!in_array($this->uploadFile_extension, $this->allowFilesOfImg())) {
                    $this->noticeByJson('ERROR_urlOfContentType');
                }
            } else {
                $this->noticeByJson('ERROR_urlOfContentType');
            }
        } else {
            $this->noticeByJson('ERROR_urlOfWeChat');
        }
    }

    protected function getImageNameOfUrl()
    {
        preg_match("/[\/]([^\/]*)[\.]?[^\.\/]*$/", $this->url_img, $m);
        return Arrays::Is($m) ? $m[1] : '';
    }

    protected function saveRemoteImg(): array
    {
        //打开输出缓冲区并获取远程图片
        ob_start();
        $context = stream_context_create(['http' => [
            'follow_location' => false // don't follow redirects
        ]]);
        readfile($this->url_img, false, $context);
        $img = ob_get_contents();
        ob_end_clean();
        $save_dir = $this->dirPathOfDisk();
        $save_file = $this->renameFile();
        fileHelper()->MKDir($save_dir);
        $fullName = $save_dir . $save_file;
        if (!(file_put_contents($fullName, $img) && file_exists($fullName))) {
            //移动失败
            $this->noticeByJson('saveFail');
        }
        return [
            'url' => $this->urlOfPath($save_file),
            'size' => Convert::bytesToUnit(strlen($img)),
            'md5' => md5_file($fullName),
        ];
    }

    private function _getAllowList_extension()
    {
        $upload_allowExt = dict('upload_allowExt');
        $list_MIME = dict('File_EXT_MIME');
        switch (request()->controller()) {
            case 'AdminUpload':
                if ($this->id_model > 0 && $this->id_field > 0
                    && is_array($this->entity_field) && is_array($this->setting_field)) {
                    if ($this->entity_field['formType'] != 'image_list') {
                        $upload_allowExt_model = explode('|', $this->setting_field['upload_allowExt']);
                    }
                }
                $upload_allowExt = isset($upload_allowExt_model) ? $upload_allowExt_model : $upload_allowExt[$this->accept];
                break;
            case 'AdminUploadByUEditor':
                switch (request()->get('action')) {
                    case 'uploadimage':
                        $upload_allowExt = $upload_allowExt[$this->accept];
                        break;
                    case 'uploadscrawl':
                    case 'uploadvideo':
                    case 'uploadfile':
                    default:
                        break;
                }
                break;
            default:
                $this->noticeByJson('ERROR_TYPE_NOT_ALLOWED');
                break;
        }
        in_array($this->uploadFile_extension, $upload_allowExt) ?: $this->noticeByJson('ERROR_TYPE_NOT_ALLOWED');
        in_array($this->uploadFile_type, $list_MIME[$this->uploadFile_extension]) ?: $this->noticeByJson('Error_MIME');
    }

}